﻿// Copyright (c) 2012 - 2021 Jared Zheng <jaredz at outlook dot com>
// Buddha Framework is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//          http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
//
// Create : 2012-12-01 version 0.1 Jared Zheng <jaredz at outlook dot com>
// Update : 2021-03-19 version 4.0.0 Jared Zheng <jaredz at outlook dot com>

#ifndef __PACKET_DEFINE_H__
#define __PACKET_DEFINE_H__

#pragma once

#define __PACKET_STRING_FORMAT__

#include "CommonDefine.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// 网络组包数据识别和数据包完整验证
class CPAKPackBuild : public CNETTraits::CNETPackBuild
{
public:
    enum PAK_HEAD_FLAG
    {
        // b  u   d  d  h  a
        // b  75  d  d  68 a
        PAK_HEAD_FLAG = 0xb75dd68a,
#ifdef __PACKET_STRING_FORMAT__
        PAK_HEAD_SIZE = 6,
        PAK_HEAD_BUF  = 8,
#endif
    };
    #pragma pack(push, 2)
    typedef struct tagPAK_HEAD
    {
        UInt    uFlag;
#ifdef __PACKET_STRING_FORMAT__
        Byte    bSize[PAK_HEAD_SIZE];
#else
        UInt    uSize;
#endif
    }PAK_HEAD, *PPAK_HEAD;
    #pragma pack(pop)
public:
#ifdef __PACKET_STRING_FORMAT__
    static void EncodeSize(PAK_HEAD* pHead, UInt uSize)
    {
        assert(uSize < USHRT_MAX);
        Char szBuf[PAK_HEAD_BUF] = { 0 };
        CChar::Format(szBuf, PAK_HEAD_BUF, "%-6x", uSize);
        MM_SAFE::Cpy(pHead->bSize, PAK_HEAD_SIZE, szBuf, PAK_HEAD_SIZE);
    }
    static UInt DecodeSize(PAK_HEAD* pHead)
    {
        Char szBuf[PAK_HEAD_BUF] = { 0 };
        MM_SAFE::Cpy(szBuf, PAK_HEAD_SIZE, pHead->bSize, PAK_HEAD_SIZE);
        return (UInt)CChar::ToULong(szBuf, nullptr, RADIXT_HEX);
    }
#endif
    static size_t GetHeadSize(void)
    {
        return sizeof(PAK_HEAD);
    }
    static void BuildHead(CBufWriteStream& Stream, UInt uSize)
    {
        PAK_HEAD Head;
        Head.uFlag = (UInt)PAK_HEAD_FLAG;
#ifdef __PACKET_STRING_FORMAT__
        EncodeSize(&Head, uSize);
#else
        Head.uSize = uSize;
#endif
        Stream.Write(&Head, sizeof(PAK_HEAD));
    }
public:
    CPAKPackBuild(void)
    {
        DEV_DUMP(TF("Server PackBuild Created"));
    }
    virtual ~CPAKPackBuild(void) OVERRIDE
    {
        DEV_DUMP(TF("Server PackBuild Destroyed"));
    }
    // send package head ptr, package data size
    // return package all size, include package head
    virtual size_t Build(PByte pPack, size_t stSize) OVERRIDE
    {
        PPAK_HEAD pHead = reinterpret_cast<PPAK_HEAD>(pPack);
        pHead->uFlag = (UInt)PAK_HEAD_FLAG;
#ifdef __PACKET_STRING_FORMAT__
        EncodeSize(pHead, (UInt)stSize);
#else
        pHead->uSize = (UInt)stSize;
#endif
        return (size_t)(stSize + sizeof(PAK_HEAD));
    }
    // check recv package valid check
    // return package all size, include package head
    // return 0 when check fail
    virtual size_t Check(PByte pPack, size_t stSize) OVERRIDE
    {
        PPAK_HEAD pHead = reinterpret_cast<PPAK_HEAD>(pPack);
        if (pHead->uFlag == (UInt)PAK_HEAD_FLAG)
#ifdef __PACKET_STRING_FORMAT__
        {
            UInt uSize = DecodeSize(pHead);
            return (uSize + sizeof(PAK_HEAD));
        }
        DEV_DEBUG(TF("Server PackBuild Check Failed %08X---%02X%02X%02X%02X%02X%02X[%d]"),
                  pHead->uFlag, pHead->bSize[0], pHead->bSize[1], pHead->bSize[2],
                  pHead->bSize[3], pHead->bSize[4], pHead->bSize[5], stSize);
#else
        {
            return (pHead->uSize + sizeof(PAK_HEAD));
        }
        DEV_DEBUG(TF("Server PackBuild Check Failed %08X---%08X[%d]"), pHead->uFlag, pHead->uSize, stSize);
#endif
        return 0;
    }
    // package head size
    virtual size_t HeadSize(void) const OVERRIDE
    {
        return sizeof(PAK_HEAD);
    }
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// 信令包数据头 : 按信令号将数据转换成对应包实例
class CPAKHeadBase : public CEventBase
{
public:
    // 数据包创建入口
    static CPAKHeadBase* Create(uintptr_t, CStream&, ULLong);
public:
    CPAKHeadBase(UEVENT uEvent = 0, URANK uRank = (URANK)COMMONR_MASTER, USID uSid = 0, UDATA uData = 0);
    virtual ~CPAKHeadBase(void) OVERRIDE;

    CPAKHeadBase(const CPAKHeadBase& aSrc);
    CPAKHeadBase& operator=(const CPAKHeadBase& aSrc);

    // 计算数据包大小
    virtual size_t Length(void) const OVERRIDE;
    // 将数据包序列化
    virtual void   Serialize(CStream&) OVERRIDE;
    // 是否为信令包流
    virtual bool   IsStream(void) const;
    virtual bool   Bind(CNetworkPtr& NetworkPtr, CNetParam* pNetParam);

    UEVENT   GetEvent(void) const;
    void     SetEvent(UEVENT uEvent);

    URANK    GetRank(void) const;
    void     SetRank(URANK uRank);

    USID     GetSid(void) const;
    void     SetSid(USID uSid);

    UDATA    GetData(void) const;
    void     SetData(UDATA uData);

    void     Reset(UEVENT uEvent, URANK uRank, USID uSid = 0, UDATA uData = 0);
private:
    UEVENT   m_uEvent; // 信令号
    URANK    m_uRank;  // 服务层级
    USID     m_uSid;   // 服务Id
    UDATA    m_uData;  // 保留数据
};
typedef CPAKHeadBase    CPAKHead;

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// 网络层解析数据派发定义
typedef CTNetworkEventHandler<CTNETDispatch<CPAKHeadBase, false>> CPAKHandler;

///////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "PacketDefine.inl"

#endif // __PACKET_DEFINE_H__
